﻿namespace MockingBird.Studio.UI.UserControls
{
    using System.Collections.Generic;
    using System.Drawing;
    using System.Windows.Forms;
    using MockingBird.Studio.UI.UserControls.Model;
    using MockingBird.Studio.UI.UserControls.ModelBuilders;
    using Thinktecture.Tools.Wscf.Services.ServiceDescription.Contract;


    /// <summary>
    /// Signature of any method that can handle WsdlTree events.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public delegate void WsdlTreeEventHandler(object sender, WsdlTreeEventArgs e);


    public partial class WsdlTree : UserControl
    {
        private bool wsdlTreeContainsService;
        private WsdlDocument wsdlDocument;
        private WsdlDocumentCommands wsdlDocumentCommands;
        private TreeNode serviceNode;
        private List<TreeNode> operationNodes;

        public WsdlTree()
        {
            InitializeComponent();
            wsdlTreeContainsService = false;
        }

        public event WsdlTreeEventHandler WsdlMenuClicked;

        public TreeView InnerTree
        {
            get
            {
                return this.tvwWsdl;
            }
        }

        public void LoadTree(ServiceDefinition serviceDefinition, WsdlDocumentCommands documentCommands)
        {
            WsdlDocumentBuilder builder = new WsdlDocumentBuilder();
            WsdlDocument wsdl = builder.BuildWsdlFromServiceDefinition(serviceDefinition);
            this.LoadTreeWithWsdl(wsdl, documentCommands);
        }

        public List<string> GetRequestMessageNames()
        {
            List<string> reqMessages = new List<string>();
            // Read through the WSDL Document to get all the messages
            foreach (WsdlOperation op in this.wsdlDocument.Operations)
            {
                reqMessages.Add(op.InputMessage.MessageName);

            }

            return reqMessages;

        }

        public List<string> GetResponseMessageNames()
        {
            List<string> responseMessages = new List<string>();
            foreach (WsdlOperation op in this.wsdlDocument.Operations)
            {
                if (!op.IsOneWay)
                {
                    responseMessages.Add(op.OutputMessage.MessageName);
                }
            }

            return responseMessages;
        }

        #region "private methods"
        private void LoadTreeWithWsdl(WsdlDocument targetWsdlDocument, WsdlDocumentCommands documentCommands)
        {
            this.wsdlDocument = targetWsdlDocument;
            this.wsdlDocumentCommands = documentCommands;

            this.ClearTree();

            this.BuildServiceNode();

            this.BuildOperationNodes();

            this.DisplayTree();
        }

        private void ClearTree()
        {
            if (wsdlTreeContainsService)
            {
                tvwWsdl.Nodes.Clear();
            }
        }
        protected virtual void OnWsdlMenuClicked(WsdlTreeEventArgs e)
        {
            WsdlMenuClicked(this, e);
        }

        private void BuildServiceNode()
        {
            serviceNode = new TreeNode();
            serviceNode.Name = this.wsdlDocument.Service.ServiceName;
            serviceNode.Text = this.wsdlDocument.Service.ServiceName;
        }

        private void BuildOperationNodes()
        {
            foreach (WsdlOperation wsdlOp in this.wsdlDocument.Operations)
            {
                TreeNode opNode = this.BuildOperationNode(wsdlOp);
                this.serviceNode.Nodes.Add(opNode);
            }
        }

        private void DisplayTree()
        {
            this.tvwWsdl.Nodes.Add(serviceNode);
            this.tvwWsdl.ExpandAll();
            this.wsdlTreeContainsService = true;
            this.Parent.Refresh();
        }
        private TreeNode BuildOperationNode(WsdlOperation wsdlOp)
        {
            TreeNode opNode = new TreeNode();
            opNode.Name = wsdlOp.OperationName;
            opNode.Text = wsdlOp.OperationName;

            TreeNode inputNode = this.BuildMessageNode(wsdlOp.InputMessage);
            opNode.Nodes.Add(inputNode);

            if (!wsdlOp.IsOneWay)
            {
                TreeNode outputNode = this.BuildMessageNode(wsdlOp.OutputMessage);
                opNode.Nodes.Add(outputNode);
            }
            return opNode;

        }

        private TreeNode BuildMessageNode(WsdlMessage msg)
        {
            TreeNode messageNode = new TreeNode();
            messageNode.Name = msg.MessageName;
            messageNode.Text = msg.MessageName;
            //messageNode.
            return messageNode;

        }

        private void HandleWsdlNodeSelection(TreeNode selectedNode, int nodeLevel, Point menuDisplayPoint)
        {
            WsdlLevel level = (WsdlLevel)nodeLevel;
            this.ShowMenuForWsdlNode(selectedNode.Name, level, menuDisplayPoint);
        }

        /// <summary>
        /// Constructs the context menu 
        /// </summary>
        /// <param name="level"></param>
        private void ShowMenuForWsdlNode(string itemName, WsdlLevel level, Point menuDisplayPoint)
        {
            wsdlContextMenu.Clear();

            switch (level)
            {
                case WsdlLevel.Service:
                    if (this.wsdlDocumentCommands.ServiceCommands.Count > 0)
                    {
                        this.wsdlContextMenu.BuildUp(level, itemName, this.wsdlDocumentCommands.ServiceCommands);
                        wsdlContextMenu.Show(tvwWsdl, menuDisplayPoint);
                    }
                    break;
                case WsdlLevel.Operation:
                    if (this.wsdlDocumentCommands.OperationCommands.Count > 0)
                    {
                        this.wsdlContextMenu.BuildUp(level, itemName, this.wsdlDocumentCommands.OperationCommands);
                        wsdlContextMenu.Show(tvwWsdl, menuDisplayPoint);
                    }
                    break;
                case WsdlLevel.Message:
                    if (this.wsdlDocumentCommands.MessageCommands.Count > 0)
                    {
                        this.wsdlContextMenu.BuildUp(level, itemName, this.wsdlDocumentCommands.MessageCommands);
                        wsdlContextMenu.Show(tvwWsdl, menuDisplayPoint);
                    }
                    break;
                case WsdlLevel.MessagePart:
                    if (this.wsdlDocumentCommands.MessagePartCommands.Count > 0)
                    {
                        this.wsdlContextMenu.BuildUp(level, itemName, this.wsdlDocumentCommands.MessagePartCommands);
                        wsdlContextMenu.Show(tvwWsdl, menuDisplayPoint);
                    }
                    break;
                case WsdlLevel.MessagePartItem:
                    if (this.wsdlDocumentCommands.MessagePartItemCommands.Count > 0)
                    {
                        this.wsdlContextMenu.BuildUp(level, itemName, this.wsdlDocumentCommands.MessagePartItemCommands);
                        wsdlContextMenu.Show(tvwWsdl, menuDisplayPoint);
                    }

                    break;
                default:
                    break;
            }
        }

        private void HandleContextMenuClick(ToolStripItemClickedEventArgs e)
        {
            WsdlTreeEventArgs args = this.wsdlContextMenu.ConvertItemClickEvent(e);
            this.OnWsdlMenuClicked(args);
        }
        #endregion
    }
}
